//@version=5
indicator(title='ↈↇↁ Fourier Smoothed Stochastic [Algo Alert]', shorttitle='ↈↇↁ FSTOCH [Algo Alert]', precision = 0)

//======================================================================================================================//
//                                              FOURIER TRANSFORM
//======================================================================================================================//

//Fast Fourier Transform
import jdehorty/KernelFunctions/2 as kernel
import TradingView/ta/5

DFT(x, y, Nx, _dir) =>
    float _arg = 0.0
    float _cos = 0.0
    float _sin = 0.0
    float xArr_i = 0.0
    float yArr_i = 0.0
    xArr = array.new_float(array.size(x))
    yArr = array.new_float(array.size(y))

    for i = 0 to Nx - 1 by 1
        xArr_i := 0.0
        yArr_i := 0.0
        kx = float(i) / float(Nx)
        _arg := -_dir * 2 * math.pi * kx
        for k = 0 to Nx - 1 by 1
            _cos := math.cos(k * _arg)
            _sin := math.sin(k * _arg)
            xArr_i += array.get(x, k) * _cos - array.get(y, k) * _sin
            yArr_i += array.get(x, k) * _sin + array.get(y, k) * _cos
            yArr_i
        array.set(xArr, i, xArr_i)
        array.set(yArr, i, yArr_i)

    if _dir == 1
        for i = 0 to Nx - 1 by 1
            array.set(x, i, array.get(xArr, i) / float(Nx))
            array.set(y, i, array.get(yArr, i) / float(Nx))
    else
        for i = 0 to Nx - 1 by 1
            array.set(x, i, array.get(xArr, i))
            array.set(y, i, array.get(yArr, i))

//======================================================================================================================
//                                                 FOURIER INPUTS
//======================================================================================================================

N = input.int(1,"Fourier Period", group = "Fourier")
xval = input.source(close,"Fourier X Series",tooltip = "i.e. the source of the discrete Fourier"+
 " transform (with the Y Series being the bars through time.)", group = "Fourier")

smoothing = input.int(-1,"Kernel Smoothing", group = "Fourier")

//======================================================================================================================
//                                                 FOURIER CALCULATIONS
//======================================================================================================================

// Fourier transform
x = array.new_float(N, 0.0)
y = array.new_float(N, 0.0)
for i = 0 to N - 1
    array.set(x, i, xval[i])
    array.set(y, i, 0.0)

DFT(x, y, N, 1)

mag = array.new_float(N, 0.0)
for i = 0 to N - 1
    mag_i = math.sqrt(math.pow(array.get(x, i), 2) + math.pow(array.get(y, i), 2))
    array.set(mag, i, mag_i)

dft = array.get(mag,0)
dfts = kernel.rationalQuadratic(dft,25,1,smoothing)

//Full Stochastic Calculation
volshow = input.bool(true, "Show volume?", group = "Volume Oscillator")
emalength = input(7, "Smoothing", group = "Stochastic")
lookback_period = input.int(14, title = "Lookback Period", minval=1, group = "Stochastic")
m1 = input.int(3, minval=1, group = "Stochastic")
m2 = input.int(3, minval=1, group = "Stochastic")

k = ta.sma(ta.stoch(dfts, high, low, lookback_period), m1) // make a separate wavelet for source, high and low
d = ta.sma(k, m2)
d := ta.ema2(d, emalength)

//Volume Oscillator
var cumVol = 0.
cumVol += nz(volume)
shortlen = 5
longlen = 10
short = ta.ema(volume, shortlen)
long = ta.ema(volume, longlen)
osc = 100 * (short - long) / long

//Histogram/Columns
color hiscol1 = color.rgb(255, 255, 255, 75)
color hiscol2 = color.rgb(131, 214, 255, 75)
color hiscol3 = color.rgb(255, 255, 255, 85)
color hiscol4 = color.rgb(131, 214, 255, 85)
plot(volshow ? osc: na, color= (osc > 0 ? (osc > osc[1] ? hiscol1 : hiscol3) : (osc < osc[1] ? hiscol2 : hiscol4)), style = plot.style_columns)

//Plots
bullcolor = color.rgb(0, 171, 6)
bearcolor = color.rgb(164, 0, 0)
obcolor = color.rgb(204, 0, 0, 90)
oscolor = color.rgb(0, 195, 13, 90)
barcolor(color = d > d[1] ? color.rgb(0, 159, 5): color.rgb(138, 0, 0))

p1 = plot(d-50, color=color.new(#000000, 20), linewidth = 1)
p2 = plot(d[1]-50, color= color.new(#000000, 20), linewidth = 1)

plotchar(ta.crossover(d,d[1]) and barstate.isconfirmed ? d-50 : na, "OB", char = "⦿", location = location.absolute, color = bullcolor, size = size.tiny, offset = -1)
plotchar(ta.crossover(d[1],d) and barstate.isconfirmed ? d-50 : na, "OB", char = "⦿", location = location.absolute, color = bearcolor, size = size.tiny, offset = -1)
 
p3 = plot(30, color = obcolor)
p33 = plot(20, color = color.new(#bc0000, 100))
pX = plot(12, color = color.new(#a90000, 100))
pXX = plot(-12, color = color.new(#029100, 100))
p4 = plot(-20, color = color.new(#029100, 100))
p44 = plot(-30, color = oscolor)
plot(0, color = color.new(color.gray,85))

fill(p1, p2, top_value = 30, bottom_value = -30, top_color = color.rgb(239, 0, 0), bottom_color = color.rgb(0, 191, 6))
fill(p3, p33, color= obcolor)
fill(p4, p44, color= oscolor)
fill(pX, p33, color = color.rgb(204, 0, 0, 95))
fill(pXX, p4, color = color.rgb(0, 195, 13, 95))

alertcondition(ta.crossover(d,d[1]), title="Buy!", message="Go Long! {{exchange}}:{{ticker}}")
alertcondition(ta.crossover(d[1],d), title="Sell!", message="Go Short! {{exchange}}:{{ticker}}")